import os
import time
import json
import asyncio
import threading
from flask import Flask, request, jsonify, render_template
from flask_cors import CORS
from client_command import ClientCommand, logger


class CommandServer:
    def __init__(self, serials_config_path: str = "./configs/parameters.yaml",
                 code_config_path: str = "./configs/settings.yaml",
                 flask_host: str = "0.0.0.0", flask_port: int = 9090):
        """
        初始化Command服务类（已删除所有帧相关属性）
        :param serials_config_path: 串口配置文件路径
        :param code_config_path: 指令配置文件路径
        :param flask_host: Flask服务IP
        :param flask_port: Flask服务端口
        """
        # 1. Flask服务基础配置
        self.app = Flask(__name__)
        CORS(self.app)  # 允许跨域
        self.flask_host = flask_host
        self.flask_port = flask_port

        # 2. ClientCommand相关属性（核心：仅保留设备连接所需）
        self.client = None  # ClientCommand实例（设备控制核心）
        self.serials_config_path = serials_config_path
        self.code_config_path = code_config_path

        # 3. 绑定路由（帧相关路由已删除，仅保留设备控制/状态查询路由）
        self._register_routes()

    def _register_routes(self):
        """注册所有API路由（无帧相关路由）"""
        # 首页路由
        self.app.add_url_rule('/', 'index', self.index)
        # 服务启停路由（重新实现：无帧线程逻辑）
        self.app.add_url_rule('/start', 'start_command_server', self.start_command_server, methods=["GET"])
        self.app.add_url_rule('/stop', 'stop_command_server', self.stop_command_server, methods=["GET"])
        # 设备控制与状态查询路由（核心保留）
        self.app.add_url_rule('/control', 'control_device', self.control_device, methods=["POST"])
        self.app.add_url_rule('/control', 'get_device_status', self.get_device_status, methods=["GET"])
        self.app.add_url_rule('/control/check', 'get_check_status', self.get_check_status, methods=["GET"])
        self.app.add_url_rule('/control/init', 'get_init_status', self.get_init_status, methods=["GET"])
        # 存储路径查询路由（核心保留）
        self.app.add_url_rule('/save', 'get_save_dir', self.get_save_dir, methods=["GET"])

    def _init_client(self):
        """初始化ClientCommand（设备连接核心，无帧相关逻辑）"""
        try:
            self.client = ClientCommand(
                serials_config_path=self.serials_config_path,
                code_config_path=self.code_config_path
            )
            self.client.connect()
            # 验证初始化结果
            if self.client and self.client.connected:
                logger.info("🎉 ClientCommand初始化成功，设备已就绪")
            else:
                logger.error("❌ ClientCommand初始化失败，connected为False")
                raise Exception("ClientCommand connected状态为False")
        except Exception as e:
            logger.error(f"❌ _init_client失败: {str(e)}", exc_info=True)
            raise  # 初始化失败时终止服务启动

    def index(self):
        """首页渲染（无帧相关修改）"""
        return render_template('/index/media.html')

    def start_command_server(self):
        """启动Command服务（重新实现：仅初始化设备，无帧线程）"""
        # 错误1：设备已初始化且连接
        if self.client and self.client.connected:
            return jsonify({
                "status": "warning",
                "success": False,
                "error": "控制服务已初始化并连接，无需重复启动"
            }), 400

        # 核心：初始化设备（无帧线程启动逻辑）
        try:
            self._init_client()
            return jsonify({
                "status": "success",
                "success": True,
                "message": "Command服务启动成功（设备已连接，无帧处理逻辑）"
            }), 200
        except Exception as e:
            return jsonify({
                "status": "failed",
                "success": False,
                "error": f"Command服务启动失败：{str(e)}"
            }), 503

    def stop_command_server(self):
        """停止Command服务（重新实现：仅断开设备连接，无帧线程停止）"""
        # 错误1：设备未初始化/未连接
        if not self.client or not self.client.connected:
            return jsonify({
                "status": "warning",
                "success": False,
                "error": "控制服务未连接，无需停止"
            }), 400

        # 核心：断开设备连接（无帧缓存/线程清理逻辑）
        try:
            self.client.disconnect()
            self.client = None  # 重置client实例
            logger.info("🔌 Command服务已停止，设备连接已断开")
            return jsonify({
                "status": "success",
                "success": True,
                "message": "Command服务停止成功（设备已断开连接）"
            }), 200
        except Exception as e:
            return jsonify({
                "status": "failed",
                "success": False,
                "error": f"Command服务停止失败：{str(e)}"
            }), 500

    def control_device(self):
        """前端发送控制指令接口（无修改，核心保留）"""
        print("===== 收到 POST /control 请求 =====")

        # 错误1：设备未初始化/未连接
        if not self.client:
            return jsonify({
                "status": "device_not_initialized",
                "success": False,
                "error": "设备未初始化（ClientCommand实例不存在）"
            }), 503
        if not self.client.connected:
            return jsonify({
                "status": "device_not_connected",
                "success": False,
                "error": "设备未连接（初始化未完成或连接失败）"
            }), 503

        # 错误2：请求体为空
        data = request.get_json()
        if not data:
            return jsonify({
                "status": "empty_request_body",
                "success": False,
                "error": "请求体不能为空，请提供JSON格式数据"
            }), 400

        # 错误3：缺少必要参数
        control_type = data.get("control_type")
        name = data.get("name")
        action = data.get("action")
        missing = []
        if not control_type:
            missing.append("control_type")
        if not name:
            missing.append("name")
        if not action:
            missing.append("action")
        if missing:
            return jsonify({
                "status": "missing_parameters",
                "success": False,
                "error": f"缺少必要参数：{', '.join(missing)}",
                "required": ["control_type", "name", "action"]
            }), 400

        try:
            # 分发指令（核心逻辑保留）
            if control_type == "key":
                self.client._send_message(self.client.commander.key_message_dict, name, action)
            elif control_type == "power":
                self.client._send_message(self.client.commander.power_message_dict, name, action)
            elif control_type == "linux":
                self.client._send_message(self.client.commander.linux_message_dict, name, action)
            elif control_type == "flash":
                self.client._send_message(self.client.commander.flash_message_dict, name, action)
            else:
                return jsonify({
                    "status": "unsupported_control_type",
                    "success": False,
                    "error": f"不支持的控制类型：{control_type}",
                    "supported_types": ["key", "power", "linux", "flash"]
                }), 400

            # 成功响应
            return jsonify({
                "status": "success",
                "success": True,
                "message": f"指令已发送（{control_type} - {name}:{action}）"
            }), 200

        except KeyError as e:
            return jsonify({
                "status": "command_key_not_found",
                "success": False,
                "error": f"指令字典中未找到匹配项：{(name, action)}（{control_type}）",
                "details": str(e)
            }), 404
        except Exception as e:
            return jsonify({
                "status": "command_send_failed",
                "success": False,
                "error": f"指令发送过程异常：{str(e)}",
                "control_type": control_type,
                "name": name,
                "action": action
            }), 500

    def get_device_status(self):
        """前端获取设备状态接口（无修改，核心保留）"""
        # 错误1：设备未初始化
        if not self.client:
            return jsonify({
                "status": "device_not_initialized",
                "success": False,
                "error": "设备未初始化（ClientCommand实例不存在）"
            }), 503

        # 错误2：Commander未初始化
        if not self.client.commander:
            return jsonify({
                "status": "commander_not_initialized",
                "success": False,
                "error": "Commander未初始化，无法获取设备状态"
            }), 503

        # 错误3：串口未初始化
        if not self.client.serial:
            return jsonify({
                "status": "serial_not_initialized",
                "success": False,
                "error": "串口设备未初始化，无法发送状态查询指令"
            }), 503

        try:
            # 异步获取状态（核心逻辑保留）
            loop = self.client.tasker.get_loop()
            status_list = loop.run_until_complete(
                self.client._send_message_async(self.client.commander.discrete_message_dict, "discrete", "only")
            )
            return jsonify({
                "status": "success",
                "success": True,
                "data": status_list,
                "timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
            }), 200

        except asyncio.TimeoutError:
            return jsonify({
                "status": "status_fetch_timeout",
                "success": False,
                "error": "获取设备状态超时（设备无响应）"
            }), 504
        except Exception as e:
            return jsonify({
                "status": "status_fetch_failed",
                "success": False,
                "error": f"获取设备状态过程异常：{str(e)}"
            }), 500

    def get_check_status(self):
        """通过name查询check_message_dict状态（无修改，核心保留）"""
        # 基础错误检查
        if not self.client:
            return jsonify({
                "status": "device_not_initialized",
                "success": False,
                "error": "设备未初始化（ClientCommand实例不存在）"
            }), 503
        if not self.client.commander:
            return jsonify({
                "status": "commander_not_initialized",
                "success": False,
                "error": "Commander未初始化，无法获取设备状态"
            }), 503
        if not self.client.serial:
            return jsonify({
                "status": "serial_not_initialized",
                "success": False,
                "error": "串口设备未初始化，无法发送查询指令"
            }), 503

        # 验证name参数
        name = request.args.get('name')
        if not name:
            return jsonify({
                "status": "missing_name_param",
                "success": False,
                "error": "缺少name参数（请传入?name=xxx）"
            }), 400

        try:
            # 异步查询状态（核心逻辑保留）
            loop = self.client.tasker.get_loop()
            status = loop.run_until_complete(
                self.client._send_message_async(self.client.commander.check_message_dict, name, "only")
            )
            return jsonify({
                "status": "success",
                "success": True,
                "data": status,
                "name": name,
                "timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
            }), 200

        except asyncio.TimeoutError:
            return jsonify({
                "status": "check_timeout",
                "success": False,
                "error": f"查询'{name}'状态超时（设备无响应）",
                "name": name
            }), 504
        except Exception as e:
            return jsonify({
                "status": "check_failed",
                "success": False,
                "error": f"查询'{name}'状态异常：{str(e)}",
                "name": name
            }), 500

    def get_init_status(self):
        """通过name查询init_message_dict状态（无修改，核心保留）"""
        # 基础错误检查
        if not self.client:
            return jsonify({
                "status": "device_not_initialized",
                "success": False,
                "error": "设备未初始化（ClientCommand实例不存在）"
            }), 503
        if not self.client.commander:
            return jsonify({
                "status": "commander_not_initialized",
                "success": False,
                "error": "Commander未初始化，无法获取设备状态"
            }), 503
        if not self.client.serial:
            return jsonify({
                "status": "serial_not_initialized",
                "success": False,
                "error": "串口设备未初始化，无法发送查询指令"
            }), 503

        # 验证name参数
        name = request.args.get('name')
        if not name:
            return jsonify({
                "status": "missing_name_param",
                "success": False,
                "error": "缺少name参数（请传入?name=xxx）"
            }), 400

        try:
            # 异步查询状态（核心逻辑保留）
            loop = self.client.tasker.get_loop()
            status = loop.run_until_complete(
                self.client._send_message_async(self.client.commander.init_message_dict, name, "only")
            )
            return jsonify({
                "status": "success",
                "success": True,
                "data": status,
                "name": name,
                "timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
            }), 200

        except asyncio.TimeoutError:
            return jsonify({
                "status": "init_timeout",
                "success": False,
                "error": f"查询'{name}'状态超时（设备无响应）",
                "name": name
            }), 504
        except Exception as e:
            return jsonify({
                "status": "init_failed",
                "success": False,
                "error": f"查询'{name}'状态异常：{str(e)}",
                "name": name
            }), 500

    def get_save_dir(self):
        """获取主机数据存储路径（无修改，核心保留）"""
        # 基础错误检查
        if not self.client:
            return jsonify({
                "status": "device_not_initialized",
                "success": False,
                "error": "设备未初始化（ClientCommand实例不存在）"
            }), 503
        if not self.client.connected:
            return jsonify({
                "status": "device_not_connected",
                "success": False,
                "error": "设备未连接，无法获取存储路径"
            }), 503

        # 检查存储路径是否已加载
        if not hasattr(self.client, "save_dir") or self.client.save_dir is None:
            return jsonify({
                "status": "save_dir_not_loaded",
                "success": False,
                "error": "存储路径未加载（配置文件读取失败或未初始化）"
            }), 500

        try:
            save_dir = self.client.save_dir
            # 可选：检查路径存在性（仅警告）
            if not os.path.exists(save_dir):
                logger.warning(f"存储路径不存在：{save_dir}（可能未创建，不影响接口返回）")

            return jsonify({
                "status": "success",
                "success": True,
                "data": save_dir,
                "source": "saving.yaml配置（数组拼接）",
                "timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
            }), 200

        except Exception as e:
            return jsonify({
                "status": "get_save_dir_failed",
                "success": False,
                "error": f"获取存储路径异常：{str(e)}",
                "current_save_dir": str(self.client.save_dir)
            }), 500

    def run(self):
        """启动整个Command服务（核心：新增curl命令打印）"""
        try:
            # -------------------------- 新增：打印所有接口curl命令 --------------------------
            print("\n" + "="*60)
            print(f"CommandServer 所有接口 curl 调用命令（服务地址：{self.flask_host}:{self.flask_port}）")
            print("="*60 + "\n")

            # 1. 服务启停接口
            print("【1. 服务启停接口】")
            print("# 启动Command服务（初始化设备连接）")
            print(f"curl -X GET \"http://{self.flask_host}:{self.flask_port}/start\"")
            print()
            print("# 停止Command服务（断开设备连接）")
            print(f"curl -X GET \"http://{self.flask_host}:{self.flask_port}/stop\"")
            print()
            print("# 访问首页（渲染media.html）")
            print(f"curl -X GET \"http://{self.flask_host}:{self.flask_port}/\"")
            print("\n" + "-"*60 + "\n")

            # 2. 设备控制接口（POST）
            print("【2. 设备控制接口（发送指令）】")
            print("# 发送控制指令（支持control_type：key/power/linux/flash）")
            print(f"curl -X POST \"http://{self.flask_host}:{self.flask_port}/control\" \\")
            print(f"  -H \"Content-Type: application/json\" \\")
            print(f"  -d '{{\"control_type\": \"key\", \"name\": \"light\", \"action\": \"on\"}}'")
            print("\n" + "-"*60 + "\n")

            # 3. 设备状态查询接口
            print("【3. 设备状态查询接口】")
            print("# 获取设备整体状态（discrete_message_dict）")
            print(f"curl -X GET \"http://{self.flask_host}:{self.flask_port}/control\"")
            print()
            print("# 查询指定name的check状态（需替换<name>，如\"fan\"）")
            print(f"curl -X GET \"http://{self.flask_host}:{self.flask_port}/control/check?name=<name>\"")
            print()
            print("# 查询指定name的init状态（需替换<name>，如\"motor\"）")
            print(f"curl -X GET \"http://{self.flask_host}:{self.flask_port}/control/init?name=<name>\"")
            print("\n" + "-"*60 + "\n")

            # 4. 存储路径查询接口
            print("【4. 存储路径查询接口】")
            print("# 获取主机数据存储路径")
            print(f"curl -X GET \"http://{self.flask_host}:{self.flask_port}/save\"")
            print("\n" + "="*60 + "\n")

            # -------------------------- 原有逻辑保留 --------------------------
            # 1. 初始化ClientCommand（设备连接核心）
            self._init_client()

            # 2. 打印注册的路由列表（便于调试）
            print("已注册的路由列表：")
            for rule in self.app.url_map.iter_rules():
                print(f"URL: {rule.rule} | 方法: {list(rule.methods)}")

            # 3. 启动Flask服务
            self.app.run(host=self.flask_host, port=self.flask_port, debug=False)
        except Exception as e:
            logger.error(f"❌ Command服务启动失败：{str(e)}", exc_info=True)
            exit(1)



# --------------------------
# 全局实例化command_server（供外部导入，无修改）
# --------------------------
command_server = CommandServer(
    serials_config_path="./configs/parameters.yaml",
    code_config_path="./configs/settings.yaml",
    flask_host="0.0.0.0",
    flask_port=9090
)
print("CommandServer：实例化完成，等待主程序启动服务")


# --------------------------
# 外部调用入口（模块单独运行时使用，无修改）
# --------------------------
if __name__ == "__main__":
    command_server.run()